home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 20
/
Cream of the Crop 20 (Terry Blount) (1996).iso
/
utility
/
freedos.zip
/
COM050.ZIP
/
LOADHIGH.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-01-17
|
15KB
|
516 lines
/*
LOADHIGH.C - command that loads a DOS executable into upper memory.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* LOADHIGH.C
*
*
* Comments
*
* ??/??/96 (Svante Frey) -------------------------------------------------
* began.
*
* 01/17/96 (Tim Norman) --------------------------------------------------
* plugged into COMMAND.COM
*
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <fcntl.h>
#include <dos.h> /* must have those MK_FP() macros */
#include "command.h" /* command shell interface functions */
#include "loadhigh.h" /* contains macros, global variables, etc */
/* This module takes care of both the LOADHIGH and the LOADFIX command,
* since those two commands have much in common.
*
* The global variable 'loadfix_flag' is used to keep track of which
* command is currently executing. If this variable is non-zero, it's
* LOADFIX, otherwise LOADHIGH.
*/
/* This is the loadhigh handler */
#pragma argsused
void loadhigh(int argc, char *argv[128], char *args)
{
loadfix_flag = 0;
lh_lf(args);
}
/* This is the loadfix handler */
#pragma argsused
void loadfix(int argc, char *argv[128], char *args)
{
loadfix_flag = 1;
lh_lf(args);
}
/* This is the "real" handler of the two commands. The argument is
* the original command line.
*/
int lh_lf(char *args)
{
int rc = err_out_of_memory;
char *fullname = malloc(128);
char **paths = malloc(128 * sizeof(*paths));
filename = malloc(128);
if (paths && fullname && filename)
{
if (initialise() == OK)
{
if ((rc = parseArgs(args)) == OK)
{
/* command line was OK - try to find the file */
get_paths(paths);
if (find_which(paths, filename, fullname) == 1)
{
/* a file was found - allocate the memory */
if (loadfix_flag)
rc = loadfix_prepare();
else rc = loadhigh_prepare();
/* finally, execute the file */
if (!rc) rc = exec(fullname, newcmdline, 0);
}
else rc = err_file_not_found;
}
}
cleanup();
free(paths);
free(fullname);
free(filename);
}
/* if any error occurred, rc will hold the error code */
if (rc) lh_error(rc);
return rc;
}
int initialise(void)
{
int rc;
/* reset global variables */
swShrink = swLoad = 0;
allocatedBlocks = 0;
upper_flag = 1;
/* Save the UMB link state and the DOS malloc strategy, to restore them later */
old_link = DosSetUMBLink(1);
old_strat = DosSetStrategy(0);
/* Allocate dynamic memory for some arrays */
if (!(umbRegion = malloc(64 * sizeof(*umbRegion))))
return err_out_of_memory;
if (!(block = malloc(256 * sizeof(*block))))
return err_out_of_memory;
/* find the UMB regions */
if ((rc = findUMBRegions()) != 0)
return rc;
return OK;
}
void cleanup(void)
{
int i;
/* free any memory that was allocated to prevent the program from using it */
for (i = 0; i < allocatedBlocks; i++)
DosFree(block[i]);
/* free dynamic arrays */
free(umbRegion);
free(block);
/* Restore UMB link state and DOS malloc strategy to their
original values. */
DosSetUMBLink(old_link);
DosSetStrategy(old_strat);
}
/* lh_error(): print error messages to stderr */
void lh_error(int errcode)
{
if (errcode > err_help)
fprintf (stderr, "ERROR: ");
switch(errcode)
{
case err_invalid_parms:
fprintf (stderr, "%s\n", BADUSAGE);
/* fall-through to show usage */
case err_help:
fprintf (stderr, "%s\n\n", loadfix_flag? loadfix_usage : loadhigh_usage);
break;
case err_file_not_found:
fprintf (stderr, "%s\n", FILENOTFOUND);
break;
case err_out_of_memory:
fprintf (stderr, "%s\n", OUTOFMEMORY);
break;
case err_mcb_chain: /* error while searching the MCB chain */
fprintf (stderr, "%s\n", BADMCBCHAIN);
break;
default:
fprintf (stderr, "error code %d\n", errcode);
}
}
/* findUMBRegions():
*
* This routine scans the MCB chain to find all active memory regions.
* Info about the regions is written to the array "umbRegions".
*
* Each continous region is numbered. Region 0 is the conventional
* memory.
*/
int findUMBRegions(void)
{
struct UMBREGION *region = umbRegion;
struct MCB far *mcb = MK_FP(GetFirstMCB(), 0); /* get start of MCB chain */
char sig;
int i;
umbRegions = 0;
region->start = FP_SEG(mcb);
/* First, find the end of the conventional memory:
Turn UMB link off, and track the MCB chain to the end. */
DosSetUMBLink(0);
while (mcb->sig == 'M') FP_SEG(mcb) += mcb->size + 1;
if (mcb->sig != 'Z') return err_mcb_chain;
/* If the last memory block in conventional memory is "reserved",
conventional memory ends at the paragraph before the block. If
the last block is an ordinary one, conventional memory ends at
the last paragraph of the block. */
if (mcb->owner == 8 && !farmemcmp(mcb->name, "SC", 2))
region->end = FP_SEG(mcb) - 1;
else region->end = FP_SEG(mcb) + mcb->size;
region++;
region->start = 0;
/* Turn UMB link on. If MS-DOS UMBs are available, the signature of
the last conventional memory block will change from 'Z' to 'M'. */
DosSetUMBLink(1);
if (mcb->sig == 'M') { /* UMBs are available */
FP_SEG(mcb) += mcb->size + 1; /* go to next block */
/* This loop searches for the regions, by searching either for
special MCBs or 'reserved' memory regions. */
do {
sig = mcb->sig;
if (mcb->owner == 8 && !farmemcmp(mcb->name, "SC", 2)) {
/* this is a 'hole' in memory */
if (region->start) {
region->end = FP_SEG(mcb) - 1;
region++;
region->start = 0;
}
} else {
/* In MS-DOS 6.x, each UMB region starts with a 'major' mcb
that is outside the ordinary MCB chain. This mcb defines
the size of the whole region. */
struct MCB far *umb_mcb = mcb;
FP_SEG(umb_mcb)--;
if (umb_mcb->sig == 'Z' || umb_mcb->sig == 'M')
if (!farmemcmp(umb_mcb->name, "UMB ", 8)) {
/* This is the signature of the special MS-DOS MCBs */
mcb = umb_mcb;
region->start = mcb->owner;
region->end = mcb->owner + mcb->size - 1;
if ((sig = mcb->sig) == 'M') region->end--;
region++;
region->start = 0;
FP_SEG(mcb) += mcb->size;
if (sig == 'Z') break;
continue;
}
if (!region->start)
region->start = FP_SEG(mcb);
}
if (sig == 'Z') {
region->end = FP_SEG(mcb) + mcb->size;
region++;
}